#!/usr/bin/env python

import lxml.etree
import datetime
import hashlib
import imaplib
import email
import email.header
import sys
import cgi
hq = cgi.escape

# > <?xml version="1.0" encoding="utf-8"?>
# > <feed xmlns="http://www.w3.org/2005/Atom">
# > 
# >   <title>Example Feed</title> 
# >   <link href="http://example.org/"/>
# >   <updated>2003-12-13T18:30:02Z</updated>
# >   <author> 
# >     <name>John Doe</name>
# >   </author> 
# >   <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
# > 
# >   <entry>
# >     <title>Atom-Powered Robots Run Amok</title>
# >     <link href="http://example.org/2003/12/13/atom03"/>
# >     <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
# >     <updated>2003-12-13T18:30:02Z</updated>
# >     <summary>Some text.</summary>
# >   </entry>
# > 
# > </feed>

def imap_to_rss(host, username, password):
    messages = []
    
    def isotime():
        return datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
    
    class Message(object):
        def __init__(self, mesg):
            self.eml = email.message_from_string(mesg)
            charset = self.eml.get_content_charset('iso-8859-1')
            def sane_header(h):
                hv = self.eml.get(h, '')
                rv = []
                for part, encoding in email.header.decode_header(hv):
                    if encoding is not None:
                        part = part.decode(encoding).encode('utf-8')
                    part = unicode(part, 'utf-8')
                    rv.append(part)
                return unicode('').join(rv)

            self.subject = sane_header('subject')
            self.message_id = sane_header('message-id')
            
            text_parts = []
            for part in self.eml.walk():
                if part.get_content_type() != 'text/plain' and \
                        part.get_content_type() != 'message/rfc822':
                    continue
                text_parts.append(unicode(part.get_payload(decode=True).decode(charset, 'replace').encode('utf-8'), 'utf-8'))
            
            self.text = '\n'.join((hq(t) for t in text_parts))

    def write_messages():
        def ma(el, *args, **kwargs):
            ne = lxml.etree.Element(*args, **kwargs)
            el.append(ne)
            return ne
        
        def h(s):
            return hashlib.sha1(s).hexdigest()
            
        feed = lxml.etree.Element("feed")
        feed.attrib['xmlns'] = "http://www.w3.org/2005/Atom"
        
        ma(feed, 'title').text = 'IMAP: %s' % host
        ma(feed, 'updated').text = isotime()
        author = ma(feed, 'author')
        ma(author, 'name').text = 'imapatom.py'
        ma(feed, 'id').text = 'http://example.com/' # FIXME
        
        for message in messages:
            entry = ma(feed, 'entry')
            ma(entry, 'title').text = message.subject
            ma(entry, 'id').text = h(message.message_id)
            ma(entry, 'updated').text = isotime() # FIXME
            ma(entry, 'summary').text = '<br/>\n'.join(message.text.split('\n'))
        et = lxml.etree.ElementTree(feed)
        et.write(sys.stdout, xml_declaration=True)

        
    imap = imaplib.IMAP4_SSL(host=host, port=993)
    imap.login(username, password)
    imap.select()
    typ, data = imap.search(None, 'ALL')
    if typ != 'OK':
        return None

    for num in reversed(data[0].split(' ')[-10:]):
        typ, data = imap.fetch(num, '(RFC822)')
        if typ != 'OK':
            continue
        try:
            mesg = data[0][1]
        except IndexError:
            continue
        parsed = Message(mesg)
        messages.append(parsed)

    write_messages()

if __name__ == '__main__':
    imap_to_rss(*sys.argv[1:])
    
